package com.oa.leave.service;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.servlet.http.HttpSession;

import org.activiti.engine.HistoryService;
import org.activiti.engine.IdentityService;
import org.activiti.engine.ManagementService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.impl.persistence.entity.IdentityLinkEntity;
import org.activiti.engine.impl.persistence.entity.TaskEntity;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.NativeTaskQuery;
import org.activiti.engine.task.Task;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.oa.leave.dao.LeaveRepository;
import com.oa.leave.dto.LeaveDTO;
import com.oa.leave.entity.Leave;
import com.oa.organization.dao.OrganizationDao;
import com.oa.system.dao.UserInfoDao;
import com.oa.util.SessionUtil;

@Transactional
@Service
public class LeaveService implements ILeaveService {

	/**
	 * 系统服务
	 */
	@Autowired
	private LeaveRepository leaveRepository;
	@Resource
	private UserInfoDao userInfoDao;
	@Resource
	private OrganizationDao organizationDao;
	@Resource
	private HttpSession session;

	/**
	 * 流程服务
	 */
	@Autowired
	private IdentityService identityService;
	@Autowired
	private RuntimeService runtimeService;

	@Autowired
	private TaskService taskService;
	@Autowired
	private RepositoryService repositoryService;
	@Resource
	private ManagementService managementService;
	@Resource
	private HistoryService historyService;

	/*----------------------------------------------系统业务--------------------------------------------*/
	@Override
	public void save(Leave leave) {
		leaveRepository.save(leave);
	}

	@Override
	public void delete(Long id) {
		Leave leave = leaveRepository.findOne(id);
		if (leave != null) {
			leaveRepository.delete(leave);
		}
	}

	@Override
	@Transactional(readOnly = true)
	public Leave findOne(Long id) {
		return leaveRepository.findOne(id);
	}

	@Override
	@Transactional(readOnly = true)
	public Page<Leave> findLeave(String userId, Pageable pageable) {
		return leaveRepository.findLeave(userId, pageable);
	}

	@Override
	@Transactional(readOnly = true)
	public String getDeptManager(String detName) {
		return userInfoDao.findOne(organizationDao.findByName(detName).getLeadId()).getRole().getRole();
	}

	@Override
	public Page<Leave> findLeaveHistory(Specification<Leave> specification, Pageable pageable) {
		return leaveRepository.findAll(specification, pageable);
	}

	@Override
	public Specification<Leave> getWhereClause(Leave leave) {
		return new Specification<Leave>() {
			@Override
			public Predicate toPredicate(Root<Leave> root, CriteriaQuery<?> cq, CriteriaBuilder cb) {
				List<Predicate> predicates = new ArrayList<>();
				if (leave.getUserId() != null && leave.getUserId().trim().length() > 0) {
					Predicate p1 = cb.like(root.get("userId").as(String.class), "%" + leave.getUserId() + "%");
					predicates.add(p1);
				}
				if (leave.getState() != null && leave.getState().trim().length() > 0) {
					Predicate p3 = cb.like(root.get("state").as(String.class), leave.getState());
					predicates.add(p3);
				}
				if (leave.getApplyTime() != null) {
					Calendar calendar = Calendar.getInstance();
					calendar.setTime(leave.getApplyTime());
					calendar.add(Calendar.DATE, 1);
					Date tomorrow = new Date(new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(calendar.getTime()));

					Predicate p4 = cb.between(root.get("applyTime"), leave.getApplyTime(), tomorrow);
					predicates.add(p4);
				}
				Predicate[] aPredicates = new Predicate[predicates.size()];
				return cb.and(predicates.toArray(aPredicates));
			}
		};
	}

	@Override
	public Page<Leave> findLateLeave() {
		Page<Leave> page = leaveRepository.findLeave(SessionUtil.getName(session),
				new PageRequest(0, 5, Direction.DESC, "id"));

		return page;
	}

	/*----------------------------------------------流程业务--------------------------------------------*/
	@Override
	public ProcessInstance startWorkflow(Long leaveId, Map<String, Object> variables) {
		// 1.声明流程实例
		ProcessInstance processInstance = null;
		// 2.获取创建好的请假实例
		Leave leave = leaveRepository.findOne(leaveId);
		if (leave != null) {
			try {

				// 3.授权
				identityService.setAuthenticatedUserId(leave.getUserId());
				// 4.把entityid转换为业务主键(用于工作流程实例关联业务)
				String businessKey = leave.getId().toString();
				// 5.启动流程实例:processDefinitionKey, businessKey, variables
				processInstance = runtimeService.startProcessInstanceByKey("leave", businessKey, variables);
				// 6.业务实体与流程实例关联
				leave.setProcessInstanceId(processInstance.getId());
				leave.setApplyTime(new Date());
				leave.setState("审批中");
				// 7.更新到数据库
				leaveRepository.save(leave);
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				// 8.取消授权
				identityService.setAuthenticatedUserId(null);
			}
		}
		return processInstance;
	}

	@Override
	public Page<LeaveDTO> findTodoTasks(String userId, Pageable pageable) {
		List<LeaveDTO> results = new ArrayList<LeaveDTO>();
		// 根据当前人的ID查询
		// 用于原生查询的sql语句
		String sql = "select * from " + managementService.getTableName(TaskEntity.class) + " T left join  "
				+ managementService.getTableName(IdentityLinkEntity.class)
				+ " I on I.TASK_ID_ = T.ID_ where T.TASK_DEF_KEY_ != 'hrFile' and (I.GROUP_ID_ = #{group} and T.ASSIGNEE_ is null or T.ASSIGNEE_ = #{assignee});";
		// 使用原生查询查找当前用户待完成的流程任务Id
		NativeTaskQuery taskQuery = taskService.createNativeTaskQuery().sql(sql)
				.parameter("group", userInfoDao.findByFullname(userId).getRole().getRole())
				.parameter("assignee", userId);
		List<Task> tasks = taskQuery.list();
		// 根据流程的业务ID查询实体并关联
		for (Task task : tasks) {
			String processInstanceId = task.getProcessInstanceId();
			ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
					.processInstanceId(processInstanceId).active().singleResult();
			String businessKey = processInstance.getBusinessKey();
			if (businessKey == null) {
				continue;
			}
			Leave leave = leaveRepository.findOne(new Long(businessKey));
			if (leave != null) {
				LeaveDTO leaveDTO = new LeaveDTO();
				BeanUtils.copyProperties(leave, leaveDTO);
				leaveDTO.setTaskId(task.getId());
				leaveDTO.setTaskName(task.getName());
				leaveDTO.setTaskCreateTime(task.getCreateTime());
				leaveDTO.setAssignee(task.getAssignee());
				leaveDTO.setTaskDefinitionKey(task.getTaskDefinitionKey());
				leaveDTO.setSuspended(processInstance.isSuspended());
				ProcessDefinition processDefinition = getProcessDefinition(processInstance.getProcessDefinitionId());
				leaveDTO.setProcessDefinitionId(processDefinition.getId());
				leaveDTO.setVersion(processDefinition.getVersion());

				results.add(leaveDTO);
			}
		}
		// results List进行排序
		// 封装为Page返回
		return new PageImpl<LeaveDTO>(results, pageable, results.size());
	}

	/**
	 * 查询流程定义对象
	 *
	 * @param processDefinitionId
	 *            流程定义ID
	 * @return
	 */
	protected ProcessDefinition getProcessDefinition(String processDefinitionId) {
		ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
				.processDefinitionId(processDefinitionId).singleResult();
		return processDefinition;
	}

	/**
	 * 签收流程任务
	 *
	 * @param taskId
	 *            任务ID
	 * @param userId
	 *            签收人用户ID
	 * @return
	 */
	public void claim(String taskId, String userId) {
		taskService.claim(taskId, userId);

	}

	/**
	 * 完成流程任务
	 *
	 * @param taskId
	 *            任务ID
	 * @param variables
	 *            流程变量
	 * @return
	 */
	public void complete(String taskId, Map<String, Object> variables) {
		taskService.complete(taskId, variables);

	}

	@Override
	public boolean isProcessInstanceActive(String ProcessInstanceId) {
		List<ProcessInstance> processInstances = runtimeService.createProcessInstanceQuery()
				.processInstanceId(ProcessInstanceId).active().list();
		if (processInstances.size() == 0) {
			return false;
		} else {
			return true;
		}
	}

	@Override
	public boolean isProcessInstanceExist(String ProcessInstanceId) {
		List<HistoricProcessInstance> processInstances = historyService.createHistoricProcessInstanceQuery()
				.processInstanceId(ProcessInstanceId).list();
		if (processInstances.size() != 0) {
			return true;
		}
		return false;
	}

	@Override
	public Task getTask(String processInstanceId) {
		Task task = taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult();
		return task;
	}

}
